package board;

import java.util.Iterator;
import java.util.NoSuchElementException;

import piece.Piece;

class Range implements Iterable<Integer> {
    
    private final Integer stop;
    
    public Range(int stop) {
        this.stop = stop;
    }

    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            
            private Integer counter = 0;

            public boolean hasNext() {
                return (counter != stop);
            }

            public Integer next() {
                if (counter == stop)
                    throw new NoSuchElementException();
                return ++counter;
            }

            public void remove() {
            }};
    }
    
}

public class Board {
	private final static int column = 10; // board column
	private final static int row = 10; // board row
	
	
	// define move wrong type
	private static final int MOVE_SUCCESS = 1;
	private static final int MOVE_WIN = 2;
	private static final int MOVE_LOSE = 3;
	private static final int MOVE_DRAW = 4;
	private static final int MOVE_FLAG = 5;
	
	private static final int MOVE_CANNT_NULL = 0;
	private static final int MOVE_UNKWON = -1 ;
	private static final int MOVE_CANNT_OWN = -2;
	private static final int MOVE_CANNT_WATER = -3;
	private static final int MOVE_CANNT_FAR = -4;
	private static final int MOVE_CANNT_MOVE = -5;
	private static final int MOVE_CANNT_SAMEPOSITION = -6;
	private static final int MOVE_CANNT_ROAD = -7;
	private static final int ROAD_VAL = -10;
	private static final int ROAD_WATER = -11;
	private static final int ROAD_BLOCK = -12;
	private static final int ROAD_NOLINE = -13;
	private static final int MOVE_CANNT_ORIG_OUTOFBOARD = -14;
	private static final int MOVE_CANNT_TARG_OUTOFBOARD = -15;
	
	protected Piece[][] board = new Piece[column][row];
	
	// TODO record previous 5 steps for two sides
	
	
	/** Initial Constructor
	 * 
	 */
	Board() {
		for (int x = 0; x < 10; x++) {
			for (int y = 0; y < 10; y++) {
				//if (!this.isWater(x, y))
				this.board[x][y] = null;
			}
		}
	}
	
	/** Returns True 
	* if the location given by x, y 
	* is a water pool.
	*/		
	protected boolean isWater(int x, int y) {
		return ((x == 2 && y == 4) || (x == 3 && y == 4) || 
				(x == 6 && y == 4) || (x == 7 && y == 4) ||
				(x == 2 && y == 5) || (x == 3 && y == 5) ||
				(x == 6 && y == 5) || (x == 7 && y == 5));
	}
	
	/** Returns True 
	* if the location given by x, y 
	* is within the board.
	*/		
	protected boolean isInBoard(int x, int y) {
		return ((x >= 0 && y >= 0 ) && (x < column  && y < row)); 
	}
	/** Return the piece loacted at x, y
	 * Return null if there is no piece
	 //* Return "" if the location is water
	  * TODO  check outof range issue
	  */
	protected Piece getPiece(int x, int y){
		return this.board[x][y];
		
	}
	
	/** Place a piece on the board
	 *  given aspecific location
	 *  TODO Give exception when the location 
	 *  	1.	already occupied
	 // *  	2.	isWater 
	 */
	protected boolean setPiece(int x, int y, Piece piece){
		if (this.isWater(x, y))
			return false; // should return information that this is water
		Piece cur = this.getPiece(x,y);
		if (cur != null)
			return false; // should return exception that is has already occupied
		this.board[x][y] = piece;
		return true;
	}
	
	/** Move one piece 
	 * from position x1,y1
	 * to position x2,y2
	 * simply move, do not check if x2, y2 has already been occupied or water
	 */
	private boolean movePiece(int x1, int y1, int x2, int y2) {
		Piece orig = this.getPiece(x1,y1);
//		if (orig == null)
//			return false; // ex
		this.board[x2][y2] = orig;
		this.board[x1][y1] = null;
		return true; // ex
	}
	
	/** Remove one piece 
	 * of position x1,y1
	 */
	private boolean removePiece(int x1, int y1) {
		this.board[x1][y1] = null;
		return true; // ex
	}
	
	/** Calculate manhattan distance of two positon
	 *  
	 */
	private int calcDistance(int x1, int y1, int x2, int y2) {
		return Math.abs(x1-x2) + Math.abs(y1-y2);
	}
	
	/** check the road  
	 * special for scount piece
	 * test if the road is horizantal, veritical or diganl
	 * test if there is no water on the road
	 * test if there is no piece on the road
	 */
	 public int checkRoad(int x1, int y1, int x2, int y2){
		 int dx = x2 - x1; 
		 int sx = (int) Math.signum(dx);
		 int dy = y2 - y1;
		 int sy = (int) Math.signum(dy);
		 int x,y;
		 if (Math.abs(dx) !=  Math.abs(dy))
			 return ROAD_NOLINE;
		 for (int i=1; i < Math.abs(dx); i++) {
				 x = x1 + i * sx; 
				 y = y1 + i * sy;
				 System.out.println("x, y: "+ x + ' ' + y);
				 if (this.getPiece(x, y)!= null) return ROAD_BLOCK;
				 if (this.isWater(x, y)) return ROAD_WATER;		 
		 }
		 return ROAD_VAL;
	 }
	
	
	/**  move/fight step
	 * TODO define return exception
	 * return true if other play can do a move
	 */
	 public int move(int x1, int y1, int x2, int y2){
		 if (!this.isInBoard(x1,y1)) return MOVE_CANNT_ORIG_OUTOFBOARD;
		 if (!this.isInBoard(x2,y2)) return MOVE_CANNT_TARG_OUTOFBOARD; 
		 Piece orig = this.getPiece(x1, y1);
	     Piece targ = this.getPiece(x2, y2);
	   
	     if (this.calcDistance(x1, y1, x2, y2) == 0) return MOVE_CANNT_SAMEPOSITION; // x1,y1 has no piece
		 if (orig == null) return MOVE_CANNT_NULL; // x1,y1 has no piece
		 if (orig.canMove()) {
			 if (orig.getMoveDistance() >= this.calcDistance(x1, y1, x2, y2)){
				 if (orig.getMoveDistance() > 1) {
					 if (this.checkRoad(x1, y1, x2, y2) != ROAD_VAL)
					 return this.checkRoad(x1, y1, x2, y2);
				 }
				 if (targ != null) {
					 if (targ.color != orig.color){
						 int result = orig.attack(targ);
						 switch (result) {
						 case Piece.FIGHT_ATTACKER_WIN:{
							 this.movePiece(x1, y1, x2, y2);// win, move original piece to target place
							 return MOVE_WIN;
						 }
						 case Piece.FIGHT_ATTACKER_LOSE:{ 
							 this.removePiece(x1,y1);
							 return MOVE_LOSE;
						 }							 
						 case Piece.FIGHT_BOTH_LOOSE: {
							 this.removePiece(x2,y2);
							 return MOVE_DRAW;
						 }
						 case Piece.FIGHT_TAKE_FLAG: {
							 this.movePiece(x1, y1, x2,y2);
							 return MOVE_FLAG;
						 }
						 // case Piece.FIGHT_TAKE_EMPTY_FIELD:
						 // case Piece.FIGHT_CANT_FIGHT:
						 default: return MOVE_UNKWON;	 
						 }
					 }
					 else return MOVE_CANNT_OWN; // cannot fight your own piece
				 }
				 else if (!this.isWater(x2, y2)){
					 this.movePiece(x1, y1, x2, y2);// Move Succesfully!
					 return MOVE_SUCCESS;
				 }
				 	  else return MOVE_CANNT_WATER;// blocked by water 				 
			 }
			 else return MOVE_CANNT_FAR; // piece cannot move this far		 
		 }
		 else return MOVE_CANNT_MOVE; // cannot move this piece 
	 }
}